/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package technotheist.geo.graph;

import gnu.trove.map.TLongObjectMap;
import gnu.trove.map.hash.TLongObjectHashMap;
import technotheist.geo.map.MapUtil;
import static technotheist.geo.map.MapUtil.*;
import technotheist.geo.map.vector.Float3Map;

/**
 *
 * @author Mitch
 */
public class GeoGrid {

    final Float3Map cellPos;
    private final GeoCell[] cells;
    private final Quad[][][] quads;
    final TLongObjectMap<HalfEdge<GeoCell, GeoTriangle>> triEdges;
    final TLongObjectMap<HalfEdge<GeoTriangle, GeoCell>> cellEdges;

    public GeoGrid(int size) {
        this.cellPos = new Float3Map(size);
        MapUtil.initUnit(cellPos);
        cells = new GeoCell[cellPos.elementCount];
        this.quads = new Quad[PANELS][size][size];
        this.triEdges = new TLongObjectHashMap<HalfEdge<GeoCell, GeoTriangle>>();
        this.cellEdges = new TLongObjectHashMap<HalfEdge<GeoTriangle, GeoCell>>();
        initCells();
        initTris();
        initCellData();
    }
    
    public Quad getQuad(int p, int u, int v) {
        return quads[p][u][v];
    }

    private void initCells() {
        for (int i = 0; i < cellPos.elementCount; i++) {
            cells[i] = new GeoCell(i, this);
        }
    }

    private void initTris() {
        for (int p = 0; p < PANELS; p++) {
            for (int u = 0; u < cellPos.sideLength; u++) {
                for (int v = 0; v < cellPos.sideLength; v++) {
                    quads[p][u][v] = new Quad(p, u, v);
                }
            }
        }
    }

    private void initCellData() {
        int[] ni = new int[HEX];
        for (int i = 0; i < cellPos.elementCount; i++) {
            cellPos.getNeighbours(i, ni);
            HalfEdge<GeoCell, GeoTriangle> te0 = triEdges.get(HalfEdge.EdgeID(ni[0], i));
            HalfEdge<GeoCell, GeoTriangle> te1 = triEdges.get(HalfEdge.EdgeID(ni[1], i));
            HalfEdge<GeoCell, GeoTriangle> te2 = triEdges.get(HalfEdge.EdgeID(ni[2], i));
            HalfEdge<GeoCell, GeoTriangle> te3 = triEdges.get(HalfEdge.EdgeID(ni[3], i));
            HalfEdge<GeoCell, GeoTriangle> te4 = triEdges.get(HalfEdge.EdgeID(ni[4], i));
            if (ni[5] >= 0) {
                HalfEdge<GeoCell, GeoTriangle> te5 = triEdges.get(HalfEdge.EdgeID(ni[0], i));
                cells[i].setTriangles(te0.face, te1.face, te2.face, te3.face, te4.face, te5.face);
            } else {
                cells[i].setTriangles(te0.face, te1.face, te2.face, te3.face, te4.face);
            }

        }
    }
    
    
    
    public class Quad {

        public final int p, u, v;
        public final GeoTriangle upper, lower;

        private Quad(int p, int u, int v) {
            this.p = p;
            this.u = u;
            this.v = v;
            int i00 = cellPos.index(p, u, v);
            int i10 = cellPos.index(p, u + 1, v);
            int i01 = cellPos.index(p, u, v + 1);
            int i11 = cellPos.index(p, u + 1, v + 1);
            this.upper = new GeoTriangle(cells[i00], cells[i11], cells[i01], GeoGrid.this);
            this.lower = new GeoTriangle(cells[i11], cells[i00], cells[i10], GeoGrid.this);
        }
    }

}
